package com.ruoyi.system.service.impl;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;

/**
 * 短信服务实现类
 * 
 * @author ruoyi
 */
@Service
public class SmsServiceImpl
{
    private static final Logger log = LoggerFactory.getLogger(SmsServiceImpl.class);

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${app.sms.api.url}")
    private String smsApiUrl;

    @Value("${app.sms.dev.enabled:false}")
    private boolean devMode;

    @Value("${app.sms.dev.fixedCode:1234}")
    private String fixedCode;

    @Value("${app.sms.code.length:4}")
    private int codeLength;

    @Value("${app.sms.code.expireTime:300}")
    private int expireTime;

    @Value("${app.sms.limit.intervalSeconds:60}")
    private int intervalSeconds;

    /** 短信验证码Redis Key前缀 */
    private static final String SMS_CODE_KEY = "sms_code:";

    /** 短信发送限制Redis Key前缀 */
    private static final String SMS_LIMIT_KEY = "sms_limit:";

    /**
     * 发送短信验证码
     * 
     * @param phone 手机号
     * @param type 短信类型（1注册 2登录 3找回密码）
     * @return 是否发送成功
     */
    public boolean sendSmsCode(String phone, String type)
    {
        // 检查发送频率限制
        String limitKey = SMS_LIMIT_KEY + phone;
        if (redisCache.hasKey(limitKey))
        {
            throw new ServiceException("发送过于频繁，请稍后再试");
        }

        // 生成验证码
        String code = generateCode();
        log.info("生成的原始验证码：{}", code);

        // 开发模式直接返回固定验证码
        if (devMode)
        {
            code = fixedCode;
            log.info("开发模式发送短信验证码，手机号：{}，验证码：{}", phone, code);
        }
        else
        {
            log.info("生产模式，准备调用短信接口，手机号：{}，验证码：{}", phone, code);
            // 调用真实短信接口
            String actualCode = callSmsApiAndGetCode(phone, code);
            if (StringUtils.isEmpty(actualCode))
            {
                throw new ServiceException("短信发送失败，请稍后重试");
            }
            code = actualCode; // 使用实际发送的验证码
            log.info("短信接口调用完成，手机号：{}，最终使用的验证码：{}", phone, code);
        }

        // 存储验证码到Redis
        String codeKey = SMS_CODE_KEY + phone + ":" + type;
        redisCache.setCacheObject(codeKey, code, expireTime, TimeUnit.SECONDS);

        log.info("短信验证码已存储到Redis，phone：{}，type：{}，code：{}，cacheKey：{}，expireTime：{}秒",
                phone, type, code, codeKey, expireTime);

        // 设置发送频率限制
        redisCache.setCacheObject(limitKey, "1", intervalSeconds, TimeUnit.SECONDS);

        return true;
    }

    /**
     * 验证短信验证码
     * 
     * @param phone 手机号
     * @param code 验证码
     * @param type 短信类型
     * @return 是否验证成功
     */
    public boolean verifySmsCode(String phone, String code, String type)
    {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(code) || StringUtils.isEmpty(type))
        {
            log.warn("短信验证码参数为空，phone：{}，code：{}，type：{}", phone, code, type);
            return false;
        }

        String codeKey = SMS_CODE_KEY + phone + ":" + type;
        String cachedCode = redisCache.getCacheObject(codeKey);

        log.info("验证短信验证码，phone：{}，code：{}，type：{}，cacheKey：{}，cachedCode：{}",
                phone, code, type, codeKey, cachedCode);

        if (StringUtils.isEmpty(cachedCode))
        {
            log.warn("验证码已过期或不存在，cacheKey：{}", codeKey);
            throw new ServiceException("验证码已过期，请重新获取");
        }

        if (!code.equals(cachedCode))
        {
            log.warn("验证码错误，输入：{}，缓存：{}", code, cachedCode);
            throw new ServiceException("验证码错误");
        }

        // 验证成功后删除验证码
        redisCache.deleteObject(codeKey);
        log.info("短信验证码验证成功，phone：{}", phone);
        return true;
    }

    /**
     * 生成随机验证码
     */
    private String generateCode()
    {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < codeLength; i++)
        {
            code.append(random.nextInt(10));
        }
        return code.toString();
    }

    /**
     * 调用短信API并获取实际发送的验证码
     */
    private String callSmsApiAndGetCode(String phone, String code)
    {
        try
        {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            String requestBody = String.format("{\"phone\":\"%s\",\"code\":\"%s\"}", phone, code);
            HttpEntity<String> request = new HttpEntity<>(requestBody, headers);

            log.info("调用短信API，请求参数：{}", requestBody);
            ResponseEntity<String> response = restTemplate.postForEntity(smsApiUrl, request, String.class);

            if (response.getStatusCode().is2xxSuccessful())
            {
                String responseBody = response.getBody();
                log.info("短信API响应：{}", responseBody);

                // 从响应中解析实际的验证码
                String actualCode = parseCodeFromResponse(responseBody);
                if (StringUtils.isNotEmpty(actualCode))
                {
                    log.info("从短信接口响应中解析到验证码：{}", actualCode);
                    return actualCode;
                }
                else
                {
                    log.warn("无法从短信接口响应中解析验证码，响应内容：{}", responseBody);
                    return null;
                }
            }
            else
            {
                log.error("短信API调用失败，状态码：{}", response.getStatusCode());
                return null;
            }
        }
        catch (Exception e)
        {
            log.error("调用短信API失败：", e);
            return null;
        }
    }

    /**
     * 从短信接口响应中解析验证码
     *
     * @param responseBody 响应内容
     * @return 验证码
     */
    private String parseCodeFromResponse(String responseBody)
    {
        if (StringUtils.isEmpty(responseBody))
        {
            return null;
        }

        try
        {
            // 尝试解析JSON响应
            // 常见的响应格式可能是：
            // {"code": 200, "data": {"verifyCode": "1234"}}
            // {"success": true, "code": "1234"}
            // {"status": "success", "smsCode": "1234"}

            // 使用正则表达式提取4位数字验证码
            java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\"(?:code|verifyCode|smsCode|captcha)\"\\s*:\\s*\"(\\d{4})\"");
            java.util.regex.Matcher matcher = pattern.matcher(responseBody);

            if (matcher.find())
            {
                return matcher.group(1);
            }

            // 如果上面的格式不匹配，尝试提取任何4位数字
            pattern = java.util.regex.Pattern.compile("(\\d{4})");
            matcher = pattern.matcher(responseBody);

            if (matcher.find())
            {
                String code = matcher.group(1);
                log.info("从响应中提取到4位数字：{}", code);
                return code;
            }

            log.warn("无法从响应中解析验证码，响应格式不匹配：{}", responseBody);
            return null;
        }
        catch (Exception e)
        {
            log.error("解析短信接口响应失败：", e);
            return null;
        }
    }
}
